package cn.net.dpi.lock.support;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StopWatch;

import javax.validation.constraints.NotBlank;
import java.util.concurrent.TimeUnit;

/**
 * 分布式锁抽象基类，支持借助 LockTrace 来追踪整个锁获取的过程
 *
 * @author dangzhicairang
 */
public abstract class AbstractLock implements Lock {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    public void setLogger(Logger logger) {
        this.logger = logger;
    }

    @Override
    public String acquire(String lockId, Integer expire, Integer timeout) {

        LockTrace lockTrace = new LockTrace(lockId, expire, timeout);
        LockTraceHolder.setLockTrace(lockTrace);
        lockTrace.start();

        String lock = null;
        long end = System.currentTimeMillis() + timeout * 1000;

        try {

            int index = 1;

            do {
                StopWatch sw = new StopWatch(String.valueOf(index));

                sw.start("第" + index + "次获取锁");
                lock = doAcquire(lockId, expire);
                sw.stop();

                if (lock == null) {
                    sw.start("第" + index + "次未获取到锁，等待");
                    try {
                        TimeUnit.MILLISECONDS.sleep(100);
                    } catch (InterruptedException e) {

                    }
                    sw.stop();
                }

                lockTrace.addStage(sw);
                index ++;

            } while (
                    lock == null && System.currentTimeMillis() <= end
            );

            lockTrace.setLockValue(lock);
            lockTrace.end(lock != null);

            this.logger.info(lockTrace.toString());

        } finally {
            LockTraceHolder.remove();
        }

        return lock;
    }

    protected abstract String doAcquire(@NotBlank String lockId, Integer expire);

}
